#!/usr/bin/python

import os
import sys
import string
from subprocess import call

### stops wizard from making changes to disk
DO_NOTHING = 1

from module.usb.USBDetector import USBDetector
from module.usb.USBSCSIDevice import USBSCSIDevice

### Simple user dialog function
def dialogNum(maxValue, allowDefault):
	selection = 0
	while 1:
		if allowDefault == True:
			print "Select [1-" + str(maxValue) + ", enter to select " + str(maxValue) + "]",
		else:
			print "Select [1-" + str(maxValue) + "]",
		
		inputValue = raw_input()
		if allowDefault and len(inputValue) == 0:
			return maxValue
		
		try:
			selection = int(inputValue)
		except ValueError:
			print "Wrong input"
			continue
		
		if selection > 0 and selection <= maxValue:
			return selection
		else:
			print "Value out of scale."

def askText(text, allowEmpty):
	while 1:
		print text,
		answer = raw_input()
		if len(answer) > 0:
			return answer
		elif allowEmpty == True:
			return ''
		else:
			print "This field can't be empty."
		
def askNum(text):
	selection = 0
	while 1:
		print text, "(positive integer)",
		try:
			selection = int(raw_input())
		except ValueError:
			print "Wrong input"
			continue
		if selection == 0:
			print "Aborted. Bye."
			sys.exit(-1)
		elif selection > 0:
			return selection
		else:
			print "Value out of scale."
		
def askYesNo(text):
	selection = 0
	while 1:
		print text, "[Y/N]:",
		selection = raw_input()
		if selection == 'Y':
			return True
		elif selection == 'N':
			return False
		else:
			print "Wrong value."

def printLimiter():
	print "------------------------------------------------------------"
			
### get list of SCSI USB devices
usbDetect = USBDetector()
usbDevices = usbDetect.search()

usbStorageDevices = []

for device in usbDevices:
	usbStorageDevices.append(USBSCSIDevice(device.getVendor(), device.getProduct(), device.getSerial()))

    
if len(usbStorageDevices) == 0:
	print "No compatible USB devices detected"
	sys.exit(-1)

printLimiter()
print "Select target device for backups:"
i = 0
for device in usbStorageDevices:
	i = i+1
	print str(i) + ".",
	print device


selected = dialogNum(i, False)-1
workingDevice = usbStorageDevices[selected]

print "You have selected", 
print workingDevice

printLimiter()
deviceSizeMB = int(workingDevice.getDeviceSize())/1024
print "Enter maximum disk size for backups. Size is in MB. Maximum", str(deviceSizeMB) + "."

deviceBackupSize = dialogNum(deviceSizeMB, True)
print "Your backup space will be", str(deviceBackupSize) + "MB."
print "Remember that whole device will be formated. It just limits space that backups will use - it doesn't affect partitions sizes."
workingDevice.setBackupSize(deviceBackupSize)


printLimiter()
print "Device detection is completed. Type 'YES' to format drive (ext3 will be used).",
confirmed = str(raw_input())

command = "mount | grep " + workingDevice.getDeviceMap() + " | wc -l"
mounted = os.popen(command).readline().rstrip("\n")

while int(mounted) > 0:
	print "USB drive is mounted! Unmount it and press ENTER to proceed.",
	raw_input()
	mounted = os.popen(command).readline().rstrip("\n")

if confirmed == "YES":
	if DO_NOTHING == 0:
		print "Please wait and DON'T remove selected USB device..."
		command = "mkfs.ext3 -F " + workingDevice.getDeviceMap()
		os.popen(command)
		command = "sync"
		os.popen(command)
		print "Formated!"
		os.mkdir("/tmp/eBackuperDrive")
		print "Mounting drive..."
		workingDevice.mount("/tmp/eBackuperDrive")
		print "Marking drive..."
		workingDevice.prepareDevice()
		print "Unmounting drive..."
		workingDevice.umount()
		os.rmdir("/tmp/eBackuperDrive")
	else:
		print "DO_NOTHING selected."
else:
	print "Aborted"
	sys.exit(-1)


BACKUP_ID = str(workingDevice.getUSBVendor()) + str(workingDevice.getUSBProduct()) + str(workingDevice.getSerial())[1] + str(workingDevice.getSerial())[-1]

printLimiter()
	
backupPath = askText('Path to backup:', False)
backupExcludePath = askText('Exclude pattern:', True)

printLimiter()

enableEncryption = askYesNo('Encrypt backups')

if enableEncryption == True:
	print "Generating encryption key"
	f = open("key.gpg", 'w')
	if f:
		name = "eBackuper"
		f.write("%echo Generating key. Be patient - it can take a long time...\nKey-Type: ELG-E\nKey-Length: 1024\nKey-Usage: encrypt\nName-Real: " + name + "\n%pubring key_" + BACKUP_ID + ".pub\n%secring key_" + BACKUP_ID + ".sec\n%commit\n%echo done\n")
		f.close()
		
		command = "gpg2 -v --batch --gen-key key.gpg"
		os.popen(command)
		
		os.remove("key.gpg")
		
		printLimiter()
		
		print "Keys have been generated. Move key_" + BACKUP_ID + ".sec to some safe place - you'll need it to decrypt backups!\nkey_" + BACKUP_ID + ".pub will be used by ebackuper - don\'t move it but copy it also!"
		encryptionKey = "key_" + BACKUP_ID + ".pub"
		
		dir = os.path.abspath('')
		encryptionKey = dir + '/' + encryptionKey
	
printLimiter()

outputFileSuffix = askText('Output file suffix:', True)
printLimiter()
preserveCount = askNum('Backup preserve count:')
usbMinPeriods = askNum('Minimal period (in minutes) between backups:')

udevRule = 'TODO'
printLimiter()

defaultPrePost = askYesNo('Do you want to use default pre/post backup command (xmessages)')

if defaultPrePost:
	postCommand = "export DISPLAY=\":0.0\" && xmessage -center -timeout 10 eBackuper fininshed backup"
	postFailCommand = "export DISPLAY=\":0.0\" && xmessage -center eBackuper failed backup with: %s"
	preCommand = "export DISPLAY=\":0.0\" && xmessage -center -timeout 10 eBackuper started backup"
else:
	postCommand = askText('Post ok backup command:', True)
	postFailCommand = askText('Post fail backup command (if you add %s it\'ll be replaced with fail reason):', True)
	preCommand = askText('Pre backup command:', True)


addUdev = askYesNo('Do you want to automatically add udev rules? It\'s required if you want to autobackup when you plug in your stick.')

conf_str = 'ACTION=="add", KERNEL=="sd[a-z]", SYSFS{idVendor}=="VENDOR_ID", SYSFS{idProduct}=="PRODUCT_ID", RUN+="DIRECTORY/ebackuper.py -c CONFIGFILE -m usb -s SERIAL_ID -v VENDOR_ID -p PRODUCT_ID", OPTIONS="last_rule"'
conf_str = string.replace(conf_str, 'VENDOR_ID', str(workingDevice.getUSBVendor()))
conf_str = string.replace(conf_str, 'PRODUCT_ID', str(workingDevice.getUSBProduct()))
conf_str = string.replace(conf_str, 'SERIAL_ID', str(workingDevice.getSerial()))
conf_str = string.replace(conf_str, 'DIRECTORY', os.path.abspath(''))
conf_str = string.replace(conf_str, 'CONFIGFILE', os.path.abspath('')+'/ebackuper.conf')


if addUdev:
	udevFile = "/etc/udev/rules.d/10_eBackuper_" + BACKUP_ID + ".rules"
	file = open(udevFile, 'w')
	if file:
		file.write("# AUTOADDED RULES BY EBACKUPER FOR USB AUTO BACKUP\n")
		file.write(conf_str)
		file.close()
		print "Added udev rule to", udevFile
		
		reloadUdev = askYesNo('Do you want me to reload udev rules? If not then you have to do it manually or reboot whole system to make usb detection to work')
		if reloadUdev:
			try:
				retCode = call("udevadm control --reload-rules", shell=True)
				if retCode != 0:
					print 'Restarting udev failed with code ' + retCode
			except OSError, e:
				print 'Restarting udev failed with: ', e
	else:
		print "!!! Error creating udev rule file ", udevFile
else:
	print "Add this rule youself to udev:"
	print conf_str

from config.ParseUSBConfig import ParseUSBConfig

configParser = ParseUSBConfig('ebackuper.conf', workingDevice.getSerial())

configParser.setBackupPath(backupPath)
configParser.setBackupExcludesPath(backupExcludePath) 

configParser.setEncrypted(enableEncryption)
if enableEncryption == True:
	configParser.setEncryptionKey(encryptionKey)
configParser.setOutputFileSuffix(outputFileSuffix)
configParser.setModuleName('usb')
configParser.setPreserveCount(preserveCount)
configParser.setUSBMinPeriod(usbMinPeriods)
configParser.setUSBProduct(workingDevice.getUSBProduct())
configParser.setUSBSerial(workingDevice.getSerial())
if addUdev:
	configParser.setUSBUdevRulePath("/etc/udev/rules.d/10_eBackuper_" + BACKUP_ID + ".rules")
configParser.setUSBVendor(workingDevice.getUSBVendor())
configParser.setPostCommand(postCommand)
configParser.setPostFailCommand(postFailCommand)
configParser.setPreCommand(preCommand)
configParser.saveChanges()	
	
print "Configuration done. You can unplug your USB stick now."